package com.ahdy.service;

import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tts.v20190823.TtsClient;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceRequest;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceResponse;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.io.UnsupportedEncodingException;

@Slf4j
@Service
public class TencentTtsService {

    @Value("${tts.secret-id}")
    private String secretId;

    @Value("${tts.secret-key}")
    private String secretKey;

    @Value("${tts.region:ap-guangzhou}")
    private String region;

    @Value("${tts.save-dir}")
    private String saveDir;

    @Value("${tts.audio-url-prefix}")
    private String audioUrlPrefix;

    @Value("${server.address}")
    private String serverHost;

    @Value("${server.port}")
    private String serverPort;

    @Value("${tts.default-voice-type:101016}")
    private Long defaultVoiceType;

    private TtsClient ttsClient;

    // 根据测试结果确定的实际限制
    private static final int SAFE_SINGLE_REQUEST_LIMIT = 150; // 安全的单次请求限制
    private static final int OPTIMAL_SEGMENT_LENGTH = 120; // 最优段落长度

    // 中文标点符号分割模式
    private static final Pattern SENTENCE_PATTERN = Pattern.compile("[。！？；;]");
    private static final Pattern COMMA_PATTERN = Pattern.compile("[，,、]");
    private static final Pattern PAUSE_PATTERN = Pattern.compile("[，,、：:]");

    // 重试和延迟配置
    private static final int MAX_RETRY_TIMES = 3;
    private static final long RETRY_DELAY_MS = 1000;
    private static final long SEGMENT_DELAY_MS = 1200; // 段落间延迟

    @PostConstruct
    public void init() throws IOException {
        log.info("初始化腾讯云TTS服务...");

        try {
            // 初始化腾讯云客户端
            Credential cred = new Credential(secretId, secretKey);

            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("tts.tencentcloudapi.com");

            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);

            this.ttsClient = new TtsClient(cred, region, clientProfile);

            // 确保保存目录存在
            Path savePath = Paths.get(saveDir).toAbsolutePath().normalize();
            Files.createDirectories(savePath);
            log.info("音频保存目录: {}", savePath);

            log.info("腾讯云TTS服务初始化完成 - 区域: {}, 单次限制: {} 字符, 最优段落: {} 字符",
                    region, SAFE_SINGLE_REQUEST_LIMIT, OPTIMAL_SEGMENT_LENGTH);

        } catch (Exception e) {
            log.error("TTS服务初始化失败", e);
            throw new IOException("TTS服务初始化失败: " + e.getMessage(), e);
        }
    }

    /**
     * 文本转语音并返回Base64编码（单段处理）
     */
    public String synthesizeToBase64(String text, Long voiceType, Long speed) throws TencentCloudSDKException {
        if (text == null || text.trim().isEmpty()) {
            throw new IllegalArgumentException("文本不能为空");
        }

        String cleanText = cleanText(text);
        if (cleanText.length() > SAFE_SINGLE_REQUEST_LIMIT) {
            throw new IllegalArgumentException(String.format(
                    "单次请求文本长度不能超过%d字符，当前长度: %d，请使用长文本合成接口",
                    SAFE_SINGLE_REQUEST_LIMIT, cleanText.length()));
        }

        log.debug("开始TTS请求，文本长度: {} 字符", cleanText.length());

        return executeWithRetry(() -> {
            TextToVoiceRequest req = createTtsRequest(cleanText, voiceType, speed);
            TextToVoiceResponse response = ttsClient.TextToVoice(req);

            if (response.getAudio() == null || response.getAudio().isEmpty()) {
                throw new TencentCloudSDKException("TTS服务返回空音频数据");
            }

            log.debug("TTS请求成功，音频大小: {} bytes", response.getAudio().length());
            return response.getAudio();
        });
    }

    /**
     * 长文本语音合成（智能分割，带进度回调）
     */
    public String synthesizeLongTextToBase64(String text, Long voiceType, Long speed)
            throws TencentCloudSDKException, IOException {
        return synthesizeLongTextToBase64(text, voiceType, speed, null);
    }

    /**
     * 长文本语音合成（带进度回调）
     */
    public String synthesizeLongTextToBase64(String text, Long voiceType, Long speed,
            Consumer<ProgressInfo> progressCallback) throws TencentCloudSDKException, IOException {

        if (text == null || text.trim().isEmpty()) {
            throw new IllegalArgumentException("文本不能为空");
        }

        String cleanText = cleanText(text);

        // 短文本直接处理
        if (cleanText.length() <= OPTIMAL_SEGMENT_LENGTH) {
            if (progressCallback != null) {
                progressCallback.accept(new ProgressInfo(1, 1, 0, "开始处理短文本"));
            }
            String result = synthesizeToBase64(cleanText, voiceType, speed);
            if (progressCallback != null) {
                progressCallback.accept(new ProgressInfo(1, 1, 100, "短文本处理完成"));
            }
            return result;
        }

        log.info("开始处理长文本，总长度: {} 字符", cleanText.length());

        // 智能分割文本
        List<String> textSegments = smartSplitText(cleanText, OPTIMAL_SEGMENT_LENGTH);
        log.info("文本智能分割完成，共 {} 段，平均长度: {} 字符",
                textSegments.size(), cleanText.length() / textSegments.size());

        // 验证分割结果
        validateSegments(textSegments);

        if (progressCallback != null) {
            progressCallback.accept(new ProgressInfo(0, textSegments.size(), 0,
                    String.format("开始处理 %d 个段落", textSegments.size())));
        }

        // 处理各段文本
        List<byte[]> audioSegments = new ArrayList<>();
        long totalStartTime = System.currentTimeMillis();

        for (int i = 0; i < textSegments.size(); i++) {
            String segment = textSegments.get(i).trim();

            if (segment.isEmpty()) {
                log.debug("跳过空段落 {}", i + 1);
                continue;
            }

            try {
                long segmentStartTime = System.currentTimeMillis();

                log.debug("处理段落 {}/{}, 长度: {} 字符, 内容预览: [{}...]",
                        i + 1, textSegments.size(), segment.length(),
                        segment.substring(0, Math.min(20, segment.length())));

                if (progressCallback != null) {
                    progressCallback.accept(new ProgressInfo(i, textSegments.size(),
                            (int) ((double) i / textSegments.size() * 100),
                            String.format("正在处理第 %d/%d 段", i + 1, textSegments.size())));
                }

                String base64 = synthesizeToBase64(segment, voiceType, speed);
                byte[] audioData = Base64.getDecoder().decode(base64);
                audioSegments.add(audioData);

                long segmentDuration = System.currentTimeMillis() - segmentStartTime;
                log.debug("段落 {} 合成完成，耗时: {}ms，音频大小: {} bytes",
                        i + 1, segmentDuration, audioData.length);

                // 段落间延迟（最后一段不延迟）
                if (i < textSegments.size() - 1) {
                    Thread.sleep(SEGMENT_DELAY_MS);
                }

            } catch (Exception e) {
                String errorMsg = String.format("段落 %d/%d 合成失败", i + 1, textSegments.size());
                log.error("{}, 内容: [{}], 错误: {}", errorMsg,
                        segment.substring(0, Math.min(50, segment.length())), e.getMessage());

                if (progressCallback != null) {
                    progressCallback.accept(new ProgressInfo(i, textSegments.size(), -1, errorMsg));
                }

                throw new RuntimeException(errorMsg + ": " + e.getMessage(), e);
            }
        }

        if (audioSegments.isEmpty()) {
            throw new RuntimeException("没有成功合成的音频段落");
        }

        long totalDuration = System.currentTimeMillis() - totalStartTime;
        log.info("所有段落合成完成，共 {} 段，总耗时: {}ms，开始合并音频",
                audioSegments.size(), totalDuration);

        if (progressCallback != null) {
            progressCallback.accept(new ProgressInfo(textSegments.size(), textSegments.size(), 95, "开始合并音频"));
        }

        // 合并音频
        String result = mergeAudioSegments(audioSegments);

        if (progressCallback != null) {
            progressCallback.accept(new ProgressInfo(textSegments.size(), textSegments.size(), 100,
                    String.format("处理完成，共 %d 段，耗时 %.1f 秒", audioSegments.size(), totalDuration / 1000.0)));
        }

        return result;
    }

    /**
     * 批量文本处理
     */
    public List<String> batchSynthesize(List<String> texts, Long voiceType, Long speed,
            Consumer<BatchProgressInfo> progressCallback) throws TencentCloudSDKException, IOException {

        if (texts == null || texts.isEmpty()) {
            throw new IllegalArgumentException("文本列表不能为空");
        }

        List<String> results = new ArrayList<>();
        List<String> errors = new ArrayList<>();

        log.info("开始批量处理，共 {} 个文本", texts.size());

        for (int i = 0; i < texts.size(); i++) {
            String text = texts.get(i);

            try {
                if (progressCallback != null) {
                    progressCallback.accept(new BatchProgressInfo(i, texts.size(),
                            String.format("处理第 %d/%d 个文本", i + 1, texts.size())));
                }

                log.debug("批量处理 {}/{}, 文本长度: {} 字符", i + 1, texts.size(), text.length());

                String result;
                if (text.length() <= OPTIMAL_SEGMENT_LENGTH) {
                    result = synthesizeToBase64(text, voiceType, speed);
                } else {
                    result = synthesizeLongTextToBase64(text, voiceType, speed);
                }

                results.add(result);
                log.debug("批量处理 {} 完成，音频大小: {} bytes", i + 1, result.length());

                // 批量间延迟
                if (i < texts.size() - 1) {
                    Thread.sleep(500);
                }

            } catch (Exception e) {
                String errorMsg = String.format("第 %d 个文本处理失败: %s", i + 1, e.getMessage());
                log.error(errorMsg);
                errors.add(errorMsg);
                results.add(null); // 保持索引对应
            }
        }

        if (progressCallback != null) {
            int successCount = (int) results.stream().mapToInt(r -> r != null ? 1 : 0).sum();
            progressCallback.accept(new BatchProgressInfo(texts.size(), texts.size(),
                    String.format("批量处理完成，成功: %d/%d", successCount, texts.size())));
        }

        if (!errors.isEmpty()) {
            log.warn("批量处理完成，但有 {} 个失败: {}", errors.size(), errors);
        }

        return results;
    }

    /**
     * 智能文本分割（优化版）
     */
    private List<String> smartSplitText(String text, int maxLength) {
        List<String> segments = new ArrayList<>();

        if (text.length() <= maxLength) {
            segments.add(text);
            return segments;
        }

        // 1. 首先按强分割符（句号、问号、感叹号）分割
        String[] sentences = SENTENCE_PATTERN.split(text);

        StringBuilder currentSegment = new StringBuilder();

        for (int i = 0; i < sentences.length; i++) {
            String sentence = sentences[i].trim();

            if (sentence.isEmpty()) {
                continue;
            }

            // 恢复分割符
            String delimiter = findDelimiterAfter(text, sentence);
            if (!delimiter.isEmpty()) {
                sentence += delimiter;
            }

            // 检查是否会超长
            if (currentSegment.length() + sentence.length() > maxLength) {
                // 保存当前段落
                if (currentSegment.length() > 0) {
                    segments.add(currentSegment.toString().trim());
                    currentSegment = new StringBuilder();
                }

                // 处理超长单句
                if (sentence.length() > maxLength) {
                    segments.addAll(splitLongSentence(sentence, maxLength));
                } else {
                    currentSegment.append(sentence);
                }
            } else {
                currentSegment.append(sentence);
            }
        }

        // 添加最后一段
        if (currentSegment.length() > 0) {
            segments.add(currentSegment.toString().trim());
        }

        return segments;
    }

    /**
     * 分割超长单句
     */
    private List<String> splitLongSentence(String sentence, int maxLength) {
        List<String> parts = new ArrayList<>();

        // 1. 尝试按逗号、冒号等弱分割符分割
        String[] weakParts = PAUSE_PATTERN.split(sentence);

        if (weakParts.length > 1) {
            StringBuilder currentPart = new StringBuilder();

            for (int i = 0; i < weakParts.length; i++) {
                String part = weakParts[i].trim();

                if (part.isEmpty()) {
                    continue;
                }

                // 恢复分割符
                if (i < weakParts.length - 1) {
                    char delimiter = findWeakDelimiter(sentence, part);
                    if (delimiter != 0) {
                        part += delimiter;
                    }
                }

                if (currentPart.length() + part.length() > maxLength) {
                    if (currentPart.length() > 0) {
                        parts.add(currentPart.toString().trim());
                        currentPart = new StringBuilder();
                    }

                    // 还是太长就按固定长度分割
                    if (part.length() > maxLength) {
                        parts.addAll(splitByFixedLength(part, maxLength));
                    } else {
                        currentPart.append(part);
                    }
                } else {
                    currentPart.append(part);
                }
            }

            if (currentPart.length() > 0) {
                parts.add(currentPart.toString().trim());
            }
        } else {
            // 2. 按固定长度分割，尽量在合适位置断开
            parts.addAll(splitByFixedLength(sentence, maxLength));
        }

        return parts;
    }

    /**
     * 按固定长度分割（智能断点）
     */
    private List<String> splitByFixedLength(String text, int maxLength) {
        List<String> parts = new ArrayList<>();

        for (int i = 0; i < text.length(); i += maxLength) {
            int end = Math.min(i + maxLength, text.length());

            // 如果不是最后一段，尝试在合适位置断开
            if (end < text.length()) {
                // 向前查找最近的空格、标点或中文字符边界
                int bestBreak = findBestBreakPoint(text, i, end);
                if (bestBreak > i + maxLength * 0.7) { // 如果断点位置合理
                    end = bestBreak;
                }
            }

            String part = text.substring(i, end).trim();
            if (!part.isEmpty()) {
                parts.add(part);
            }

            i = end - maxLength; // 调整索引，避免重复
        }

        return parts;
    }

    /**
     * 查找最佳断点
     */
    private int findBestBreakPoint(String text, int start, int defaultEnd) {
        // 从默认结束位置向前查找
        for (int i = defaultEnd - 1; i > start + defaultEnd * 0.7; i--) {
            char c = text.charAt(i);

            // 优先在标点符号后断开
            if (PAUSE_PATTERN.matcher(String.valueOf(c)).matches()) {
                return i + 1;
            }

            // 次选在空格后断开
            if (Character.isWhitespace(c)) {
                return i + 1;
            }

            // 中文字符可以任意断开
            if (c >= 0x4e00 && c <= 0x9fa5) {
                return i + 1;
            }
        }

        return defaultEnd;
    }

    /**
     * 查找强分割符
     */
    private String findDelimiterAfter(String text, String sentence) {
        int index = text.indexOf(sentence);
        if (index >= 0 && index + sentence.length() < text.length()) {
            char nextChar = text.charAt(index + sentence.length());
            if ("。！？；;".indexOf(nextChar) >= 0) {
                return String.valueOf(nextChar);
            }
        }
        return "";
    }

    /**
     * 查找弱分割符
     */
    private char findWeakDelimiter(String text, String part) {
        int index = text.indexOf(part);
        if (index >= 0 && index + part.length() < text.length()) {
            char nextChar = text.charAt(index + part.length());
            if ("，,、::".indexOf(nextChar) >= 0) {
                return nextChar;
            }
        }
        return 0;
    }

    /**
     * 验证分割结果
     */
    private void validateSegments(List<String> segments) {
        for (int i = 0; i < segments.size(); i++) {
            String segment = segments.get(i);
            if (segment.length() > SAFE_SINGLE_REQUEST_LIMIT) {
                log.warn("警告：段落 {} 长度 {} 超过安全限制 {}，可能会失败",
                        i + 1, segment.length(), SAFE_SINGLE_REQUEST_LIMIT);
            }
        }
    }

    /**
     * 合并音频段落
     */
    private String mergeAudioSegments(List<byte[]> segments) throws IOException {
        if (segments.isEmpty()) {
            throw new IOException("没有可合并的音频片段");
        }

        if (segments.size() == 1) {
            return Base64.getEncoder().encodeToString(segments.get(0));
        }

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            for (byte[] segment : segments) {
                outputStream.write(segment);
            }
            byte[] mergedAudio = outputStream.toByteArray();
            log.info("音频合并完成，总大小: {} bytes", mergedAudio.length);
            return Base64.getEncoder().encodeToString(mergedAudio);
        }
    }

    /**
     * 创建TTS请求
     */
    private TextToVoiceRequest createTtsRequest(String text, Long voiceType, Long speed) {
        TextToVoiceRequest req = new TextToVoiceRequest();
        req.setText(text);
        req.setSessionId("session_" + System.currentTimeMillis());
        req.setModelType(1L);
        req.setVoiceType(voiceType != null ? voiceType : defaultVoiceType);
        req.setCodec("mp3");
        req.setSpeed(speed != null ? speed.floatValue() : 0);
        return req;
    }

    /**
     * 带重试的执行方法
     */
    private <T> T executeWithRetry(SupplierWithException<T> supplier) throws TencentCloudSDKException {
        Exception lastException = null;

        for (int attempt = 1; attempt <= MAX_RETRY_TIMES; attempt++) {
            try {
                return supplier.get();
            } catch (TencentCloudSDKException e) {
                lastException = e;
                log.warn("TTS请求失败，第 {} 次尝试，错误: {}", attempt, e.getMessage());

                if (attempt < MAX_RETRY_TIMES) {
                    try {
                        Thread.sleep(RETRY_DELAY_MS * attempt);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        throw new TencentCloudSDKException("TTS请求失败，已重试 " + MAX_RETRY_TIMES + " 次: " +
                (lastException != null ? lastException.getMessage() : "未知错误"), lastException);
    }

    /**
     * 清理文本内容
     */
    private String cleanText(String text) {
        if (text == null)
            return "";

        return text.trim()
                .replaceAll("\\s+", " ")
                .replaceAll("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]", "")
                .replaceAll("[\uFEFF\u200B-\u200D\u2060]", "");
    }

    /**
     * 生成音频访问URL
     * 
     * @param fileName 文件名
     * @return 完整的访问URL
     */
    private String generateAudioUrl(String fileName) {
        // 构建完整的URL
        String protocol = "http://"; // 或者根据配置使用https
        String host = serverHost;
        if (host.equals("localhost") || host.equals("127.0.0.1") || host.equals("0.0.0.0")) {
            host = "192.168.0.6";
        }

        // 确保文件名使用正斜杠
        fileName = fileName.replace('\\', '/');

        // 构建完整URL
        return String.format("%s%s:%s%s%s",
                protocol,
                host,
                serverPort,
                audioUrlPrefix,
                fileName);
    }

    /**
     * 生成唯一的文件名
     */
    private String generateFileName(String text) {
        String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS").format(new Date());
        // 对中文文本进行简单处理，不进行URL编码
        String safeText = text.substring(0, Math.min(10, text.length()))
                .replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", "_");
        return String.format("tts_%s_%s.mp3", timestamp, safeText);
    }

    private String normalizePath(String path) {
        return path.replace("\\", "/") // 将反斜杠替换为正斜杠
                .replace("./", "") // 移除相对路径标记
                .replaceAll("/{2,}", "/") // 将多个连续斜杠替换为单个斜杠
                .replaceAll("^/+|/+$", ""); // 移除开头和结尾的斜杠
    }

    /**
     * 文本转语音并保存为MP3文件
     */
    public String synthesizeAndSave(String text, Long voiceType) throws TencentCloudSDKException, IOException {
        // 合成音频
        String base64Audio;
        if (text.length() <= OPTIMAL_SEGMENT_LENGTH) {
            base64Audio = synthesizeToBase64(text, voiceType, null);
        } else {
            base64Audio = synthesizeLongTextToBase64(text, voiceType, null);
        }

        // 解码音频数据
        byte[] audioData = Base64.getDecoder().decode(base64Audio);

        // 生成文件名（不包含URL编码）
        String audioFileName = generateFileName(text);

        // 确保目录存在
        File audioDir = new File(saveDir);
        if (!audioDir.exists()) {
            audioDir.mkdirs();
        }

        // 保存文件
        File audioFile = new File(audioDir, audioFileName);
        Files.write(audioFile.toPath(), audioData);
        log.info("音频文件保存成功: {}, 大小: {} bytes", audioFile.getAbsolutePath(), audioData.length);

        // 生成访问URL
        return String.format("http://%s:%s/tts-audios/%s",
                serverHost,
                serverPort,
                audioFileName);
    }

    /**
     * 创建目录
     */
    private void createDirectoryIfNotExists(String dirPath) throws IOException {
        Path path = Paths.get(dirPath);
        if (!Files.exists(path)) {
            Files.createDirectories(path);
            log.info("创建目录: {}", path);
        }
    }

    /**
     * 进度信息类
     */
    public static class ProgressInfo {
        private final int currentSegment;
        private final int totalSegments;
        private final int progressPercent;
        private final String message;

        public ProgressInfo(int currentSegment, int totalSegments, int progressPercent, String message) {
            this.currentSegment = currentSegment;
            this.totalSegments = totalSegments;
            this.progressPercent = progressPercent;
            this.message = message;
        }

        // Getters
        public int getCurrentSegment() {
            return currentSegment;
        }

        public int getTotalSegments() {
            return totalSegments;
        }

        public int getProgressPercent() {
            return progressPercent;
        }

        public String getMessage() {
            return message;
        }

        @Override
        public String toString() {
            return String.format("进度: %d/%d (%d%%) - %s",
                    currentSegment, totalSegments, progressPercent, message);
        }
    }

    /**
     * 批量进度信息类
     */
    public static class BatchProgressInfo {
        private final int currentText;
        private final int totalTexts;
        private final String message;

        public BatchProgressInfo(int currentText, int totalTexts, String message) {
            this.currentText = currentText;
            this.totalTexts = totalTexts;
            this.message = message;
        }

        // Getters
        public int getCurrentText() {
            return currentText;
        }

        public int getTotalTexts() {
            return totalTexts;
        }

        public String getMessage() {
            return message;
        }

        @Override
        public String toString() {
            return String.format("批量进度: %d/%d - %s", currentText, totalTexts, message);
        }
    }

    /**
     * 函数式接口
     */
    @FunctionalInterface
    private interface SupplierWithException<T> {
        T get() throws TencentCloudSDKException;
    }

    public String getSaveDir() {
        return normalizePath(saveDir);
    }
}
